﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using Aga.Controls.Tree;
using System.Reflection;

namespace UnrealDebugger.Panels
{
    public partial class ExplorerPanel : Panel
    {
        public class BaseNode : Node
        {
            public BaseNode()
                : base()
            {
            }

            public BaseNode(string text)
                : base(text)
            {
            }

            protected static Image _folder = null;
            protected static Image _file = null;
            protected static Image _script = null;
            protected static Image _package = null;

            static BaseNode()
            {
                Stream file = null;
                Assembly assembly = typeof(BaseNode).Assembly;

                file = assembly.GetManifestResourceStream("UnrealDebugger.Resources.Folder.png");
                _folder = Image.FromStream(file);

                file = assembly.GetManifestResourceStream("UnrealDebugger.Resources.File.png");
                _file = Image.FromStream(file);

                file = assembly.GetManifestResourceStream("UnrealDebugger.Resources.Script.png");
                _script = Image.FromStream(file);

                file = assembly.GetManifestResourceStream("UnrealDebugger.Resources.Package.png");
                _package = Image.FromStream(file);
            }
        }

        public class FolderNode : BaseNode
        {
            public FolderNode()
                : base()
            {
            }

            public FolderNode(string text)
                : base(text)
            {
            }

            public bool IsUnrealPackage()
            {
                if (Folder != null)
                {
                    foreach (DirectoryInfo dir in Folder.GetDirectories())
                    {
                        if (string.Compare(dir.Name, "Classes", true) == 0) { return true; }
                    }
                }

                return false;
            }

            public DirectoryInfo Folder { get; set; }

            public Image Icon { get { return IsUnrealPackage() ? _package : _folder; } }
        }

        public class FileNode : BaseNode
        {
            public FileNode()
                : base()
            {
            }

            public FileNode(string text)
                : base(text)
            {
            }

            public bool IsUnrealFile()
            {
                if (File != null)
                {
                    return (string.Compare(File.Extension, ".uc", true) == 0) || (string.Compare(File.Extension, ".uci", true) == 0);
                }

                return false;
            }

            public FileInfo File { get; set; }
            public string Path { get { return File.FullName; } }
            public string Size { get { return Math.Ceiling(File.Length / 1024.0F).ToString() + "K"; } }
            public Image Icon { get { return IsUnrealFile() ? _script : _file; } }
        }

        private const int MaxFileHistoryCount = 10;

        private TreeModel _model = null;
        private List<string> _recentFiles = new List<string>();

        public List<string> RecentFiles { get { return this._recentFiles; } }

        public ExplorerPanel()
            : base()
        {
            InitializeComponent();
            this.Load += new EventHandler(OnLoad);
            UnrealDebuggerIDE.Instance.OnProjectPathChanged += new UnrealDebuggerIDE.ProjectPathChangedDelegate(OnProjectChanged);
            UnrealDebuggerIDE.Instance.OnReadUserData += new UnrealDebuggerIDE.ReadUserDataDelegate(OnReadUserData);
            UnrealDebuggerIDE.Instance.OnWriteUserData +=new UnrealDebuggerIDE.WriteUserDataDelegate(OnWriteUserData);
        }

        public void OnProjectChanged(string path, string[] filter)
        {
            this.treeViewExplorer.BeginUpdate();

            this._model = new TreeModel();

            BaseNode rootNode = new BaseNode("UDK");

            this._model.Nodes.Add(rootNode);

            try
            {
                PopulateTree(path, rootNode, filter);
            }
            catch (Exception e)
            {
                ExceptionMessageBox msgBox = new ExceptionMessageBox(e);
                msgBox.ShowDialog();
            }

            this.treeViewExplorer.Model = _model;
            this.treeViewExplorer.EndUpdate();

            foreach (TreeNodeAdv node in this.treeViewExplorer.Root.Children)
            {
                node.Expand();
            }
        }

        void OnWriteUserData(SerializableDictionary<string, string> userData)
        {
            int position = 1;
            foreach (string file in this._recentFiles)
            {
                userData["RecentFile[" + position.ToString() + "]"] = file;
                position++;
            }
        }

        void OnReadUserData(SerializableDictionary<string, string> userData)
        {
            for (int position = 1; position <= MaxFileHistoryCount; ++position)
            {
                string key = "RecentFile[" + position.ToString() + "]";
                if (userData.ContainsKey(key))
                {
                    this._recentFiles.Add(userData[key]);
                }
            }
        }

        void OnLoad(object sender, EventArgs e)
        {
            this.treeViewExplorer.Model = _model;
        }

        #region Debugger Interface

        private enum IconId
        {
            Package = 0,
            Folder = 1,
            Script = 2,
            File = 3,
        }

        private void PopulateTree(string dir, BaseNode root, string[] filter)
        {
            DirectoryInfo directory = new DirectoryInfo(dir);

            foreach (DirectoryInfo d in directory.GetDirectories())
            {
                FolderNode node = new FolderNode(d.Name);
                node.Folder = d;

                PopulateTree(d.FullName, node, filter);
                root.Nodes.Add(node);
            }

            foreach (FileInfo f in directory.GetFiles())
            {
                if (filter.Contains(f.Extension))
                {
                    FileNode node = new FileNode(f.Name);
                    node.File = f;

                    root.Nodes.Add(node);
                }
            }
        }

        private void _SearchFiles(List<FileInfo> files, BaseNode node, string text)
        {
            FileNode fileNode = node as FileNode;
            FileInfo f = fileNode != null ? fileNode.File as FileInfo : null;
            
            if (f != null && f.FullName.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) 
            { 
                files.Add(f); 
            }

            foreach (BaseNode child in node.Nodes)
            {
                _SearchFiles(files, child, text);
            }
        }

        public List<FileInfo> SearchFiles(string text)
        {
            List<FileInfo> files = new List<FileInfo>();

            foreach (BaseNode node in this._model.Nodes)
            {
                _SearchFiles(files, node, text);
            }

            return files;
        }

        public Document ShowDocument(string filename)
        {
            Document doc = UnrealDebuggerIDE.Instance.GetDocumentFromFile(filename);

            if (doc != null)
            {
                UnrealDebuggerIDE.Instance.ShowDocument(doc);
            }

            return doc;
        }

        public void AddToRecentFiles(string file)
        {
            this._recentFiles.Remove(file);
            this._recentFiles.Insert(0, file);
            if (this._recentFiles.Count > MaxFileHistoryCount)
            {
                this._recentFiles.RemoveRange(MaxFileHistoryCount, this._recentFiles.Count - MaxFileHistoryCount);
            }
        }
        
       
        #endregion

        private void treeViewExplorer_DoubleClick(object sender, EventArgs e)
        {
            TreeNodeAdv node = this.treeViewExplorer.SelectedNode;
            FileNode fileNode = node != null ? node.Tag as FileNode : null;
            FileInfo f = fileNode != null ? fileNode.File : null;

            if (f != null)
            {
                ShowDocument(f.FullName);
            }
        }
    }
}
